/*
 * Timer.cpp
 *
 *  Created on: 04.05.2011
 *      Author: Hugme
 */

#include "Timer.h"

Timer::Timer() {
    state = 0;
}

void Timer::restartTimer() {
    if (state == 1) {
        Timer::abortTimer();
    }
    Timer::addTimer(chid, initialTime.it_value.tv_sec, initialTime.it_value.tv_nsec, initialTime.it_interval.tv_sec, initialTime.it_interval.tv_sec);
}

void Timer::abortTimer() {
    if (state == 1) {
        if (timer_delete(Timer::timerID) != 0) {
            fprintf(stderr, "couldn't stop timer!\n");
            perror("abortTimer");
            exit(EXIT_FAILURE);
        }
        state = 3;
    } else {
        fprintf(stderr, "should never happen!\n");
    }

}

void Timer::pauseTimer() {
    if (state == 1) {
        if (timer_gettime(Timer::timerID, &remainingTime) != 0) {
            perror("abortTimer1");
            exit(EXIT_FAILURE);
        }
        Timer::abortTimer();
        state = 2;
    } else if (state == 2) {
        fprintf(stderr, "timer already paused!\n");
    } else if (state == 3) {
        fprintf(stderr, "cannot pause aborted timer!\n");
    } else {
        fprintf(stderr, "should never happen!\n");
    }
}

timer_t Timer::getTimerID() {
    return Timer::timerID;
}

void Timer::resumeTimer() {
    if (state == 2) {
        Timer::addTimer(Timer::chid, Timer::remainingTime.it_value.tv_sec, Timer::remainingTime.it_value.tv_nsec, Timer::remainingTime.it_interval.tv_sec,
                Timer::remainingTime.it_interval.tv_nsec);
    } else {
        fprintf(stderr, "can only resume paused timer!\n");
    }
}

struct itimerspec* Timer::getRemainingTime() {
    if (state == 1) {
        if (timer_gettime(Timer::timerID, &remainingTime) != 0) {
            fprintf(stderr, "couldn't get remaining time!\n");
            exit(EXIT_FAILURE);
        }
        return &remainingTime;
    }
    if (state == 2 || state == 3){
        printf("getting time from aborted or paused timer!\n");
        return &remainingTime;
    }
    printf("timer: Fehler in getRemeaningTime, state unkorrekt -> state=%d", state);
    return NULL;
}

int Timer::getTimerState() {
    return state;
}

void Timer::addTimer(int chid, int sec, int nsec, int intervallSec, int intervallNsec) {
    if (state == 0) {
        initialTime.it_value.tv_sec = sec;
        initialTime.it_value.tv_nsec = nsec;
        initialTime.it_interval.tv_sec = intervallSec;
        initialTime.it_interval.tv_sec = intervallNsec;
    }

    Timer::chid = chid;
    Timer::sec = sec;
    Timer::nsec = nsec;
    Timer::intervallSec = intervallSec;
    Timer::intervallNsec = intervallNsec;

    // create a connection back to ourselves
    Timer::coid = ConnectAttach(0, 0, chid, 0, 0);
    if (Timer::coid == -1) {
        fprintf(stderr, "couldn't ConnectAttach to self!\n");
        perror("addTimer: connectAttach");
        exit(EXIT_FAILURE);
    }

    // set up the kind of event that we want to deliver -- a pulse
    SIGEV_PULSE_INIT (&event, Timer::coid, SIGEV_PULSE_PRIO_INHERIT, CODE_TIMER, 0);

    // create the timer, binding it to the event
    if (timer_create(CLOCK_REALTIME, &event, &timerID) == -1) {
        fprintf(stderr, "couldn't create a timer, errno %d\n", errno);
        perror("addTimer: timer_create");
        exit(EXIT_FAILURE);
    }

    // setup the timer
    timer.it_value.tv_sec = sec;
    timer.it_value.tv_nsec = nsec;
    timer.it_interval.tv_sec = intervallSec;
    timer.it_interval.tv_nsec = intervallNsec;

    // and start it!
    timer_settime(timerID, 0, &timer, NULL);
    state = 1;
}
